﻿using System;

namespace CPAIS.Model
{
    /// <summary>
    /// Represents an abstract clinical event, including timestamp, event type, etc.
    /// </summary>
    public abstract class ClinicalEvent : IComparable<ClinicalEvent>
    {        
        #region Variables in ClinicalEvent
        protected Trace owner;
        protected int day;
        protected DateTime timestamp;
        protected int typeIndex;
        #endregion

        /// <summary>
        /// Constructor with occurred day.
        /// </summary>
        /// <param name="owner">Owner trace</param>
        /// <param name="day">Day of the event occurred</param>
        protected ClinicalEvent(Trace owner, int day)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");
            // if (day < 0)
            //     throw new ArgumentOutOfRangeException("day", "Event day must be nonnegative");
            this.owner = owner;
            this.day = day;
            this.timestamp = DateTime.MinValue;
        }

        /// <summary>
        /// Constructor with occurred timestamp.
        /// </summary>
        /// <param name="owner">Owner trace</param>
        /// <param name="timestamp">Timestamp of the event occurred</param>
        protected ClinicalEvent(Trace owner, DateTime timestamp)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");
            // if (timestamp < new DateTime(1990, 1, 1))
            //     throw new ArgumentOutOfRangeException("timestamp", "Event timestamp must be later than 1990-01-01");
            this.owner = owner;
            this.day = int.MinValue;
            this.timestamp = timestamp;
        }

        /// <summary>
        /// Gets the day when this event is occurred.
        /// There are 2 ways to get it, the original day specified, or calculated
        /// by minusing occurred timestamp with admit timestamp.
        /// </summary>
        public int Day
        {
            get
            {
                if (day == int.MinValue)
                    return (int)(timestamp - owner.Admit).TotalDays;
                else
                    return day;
            }
        }

        /// <summary>
        /// Gets whether the event timestamp is available.
        /// </summary>
        public bool IsTimestampAvailable
        {
            get { return timestamp != DateTime.MinValue; }
        }

        /// <summary>
        /// Gets the timestamp when this event occurred. Note that it may be invalid.
        /// </summary>
        public DateTime Timestamp
        {
            get { return timestamp; }
        }

        /// <summary>
        /// Gets the type index of this event, the original type name is stored in LogModel.
        /// </summary>
        public int TypeIndex
        {
            get { return typeIndex; } 
        }

        /// <summary>
        /// Gets the event type name.
        /// </summary>
        public abstract string TypeName
        { 
            get; 
        }

        /// <summary>
        /// Compares two event by occurred timestamp.
        /// Used for sorting event by timestamp in ASCENDING order.
        /// </summary>
        public int CompareTo(ClinicalEvent other)
        {
            bool useTimestamp = this.IsTimestampAvailable;
            if (useTimestamp)
            {
                if (this.timestamp > other.timestamp)
                    return 1;
                else if (this.timestamp < other.timestamp)
                    return -1;
                else
                    return 0;
            }
            else
            {
                return this.day - other.day;
            }
        }
    }
}
